package com.samphanie.auiu.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.samphanie.auiu.admin.constants.MenuConstants;
import com.samphanie.auiu.admin.domain.dto.MenuDto;
import com.samphanie.auiu.admin.domain.vo.MenuVo;
import com.samphanie.auiu.admin.domain.vo.ResourceVo;
import com.samphanie.auiu.admin.service.ISysMenuService;
import com.samphanie.auiu.admin.service.ISysResourceService;
import com.samphanie.auiu.admin.service.ISysRoleMenuService;
import com.samphanie.auiu.admin.service.ISysUserRoleService;
import com.samphanie.auiu.admin.utils.SecurityUtil;
import com.samphanie.auiu.common.exception.ApiException;
import com.samphanie.auiu.mbg.mapper.SysMenuMapper;
import com.samphanie.auiu.mbg.model.SysMenu;
import com.samphanie.auiu.mbg.model.SysRole;
import com.samphanie.auiu.mbg.utils.PageUtils;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 菜单Service业务层处理
 *
 * @author zsy
 * @date 2021-05-18
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    private final ISysResourceService resourceService;
    private final ISysUserRoleService userRoleService;
    private final ISysRoleMenuService roleMenuService;

    /**
     * 查询菜单列表
     *
     * @param query
     * @return 菜单
     */
    @Override
    public List<SysMenu> selectSysMenuList(Map<String, String> query) {
        return baseMapper.selectSysMenuList(query);
    }

    @Override
    public PageUtils listPage(Map<String, Object> query) {
        PageUtils.startPage(query);
        val list = list();
        return new PageUtils(list);
    }

    @Transactional
    @Override
    public boolean createMenu(MenuDto menuDto) {
        val menu = MenuDto.fromMenu.apply(menuDto);
        menu.setParentId(menuDto.getParentId());
        // TODO 添加资源
        menu.setCreateBy(SecurityUtil.getCurrentUsername());
        return save(menu);
    }

    @Override
    public boolean edit(MenuDto menuDto) {
        val menu = MenuDto.fromMenu.apply(menuDto);
        menu.setId(menuDto.getId());
        menu.setParentId(menuDto.getParentId());
        menu.setUpdateBy(SecurityUtil.getCurrentUsername());
        return updateById(menu);
    }

    @Override
    public boolean checkHasSubMenu(Long menuId) {
        List<SysMenu> menuList = getMenuChildrenListById(menuId);
        return CollUtil.isNotEmpty(menuList);
    }

    @Override
    public List<SysMenu> getMenuChildrenListById(Long menuId) {
        return list(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, menuId));
    }

    @Override
    public List<MenuVo> treeMenuList() {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<SysMenu>()
                .orderByDesc(SysMenu::getSort)
                .orderByDesc(SysMenu::getCreateTime);
        val list = list(queryWrapper);
        // TODO 菜单数据处理
        val menuList = list.stream().map(item -> {
                    MenuVo menuVo = MenuVo.fromMenuVo.apply(item);
                    List<ResourceVo> operations = resourceService.listOperationsByMenuId(menuVo.getId());
                    menuVo.setOperations(operations);
                    return menuVo;
                }).collect(Collectors.toList());
        return getMenuNodes(menuList);
    }

    @Override
    public List<MenuVo> getUserMenuList(Long userId) {
        // 获取用户角色信息
        Set<SysRole> roles = userRoleService.getRoleList(userId).orElseThrow(() -> new ApiException("用户角色信息不存在"));
        // 获取角色菜单信息
        val roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toSet());
        List<SysMenu> menuList;
        // 判断用户是否为超级管理员
        if (roleIds.contains(1L)) {
            menuList = list();
        } else {
            Set<Long> menuIds = roleMenuService.listMenuIdsByRoleIds(roleIds);
            menuList = listByIds(menuIds);
        }
        return menuList.stream().map(menu -> MenuVo.fromMenuVo.apply(menu)).collect(Collectors.toList());
    }

    @Override
    public List<MenuVo> getUserTreeMenuList(Long userId) {
        return getMenuNodes(getUserMenuList(userId));
    }

    // 过滤出一级分类 并递归设置子分类
    private List<MenuVo> getMenuNodes(List<MenuVo> menuList) {
        return menuList.stream().filter(menu -> menu.getParentId().equals(0L) && !menu.getType().equals(MenuConstants.MenuTypeEnum.MENU.getValue()))
                .peek(menu -> menu.setChildren(convertMenuNode(menu, menuList)))
                .sorted(Comparator.comparing(MenuVo::getSort).reversed())
                .collect(Collectors.toList());
    }

    // 递归菜单子分类
    private List<MenuVo> convertMenuNode(MenuVo menu, List<MenuVo> menuList) {
        return menuList.stream()
                .filter(subMenu -> subMenu.getParentId().equals(menu.getId()) && !subMenu.getType().equals(MenuConstants.MenuTypeEnum.MENU.getValue()))
                .peek(subMenu -> subMenu.setChildren(convertMenuNode(subMenu, menuList)))
                .sorted(Comparator.comparing(MenuVo::getSort).reversed())
                .collect(Collectors.toList());
    }
}
